/*******************************************************************************
filename      StringCommentPrinter.cpp
author        Craig Williams

Brief Description:
  Prints all strings, C Style comments, and C++ Style comments from a file.
    If a file is not specified, Parser.c will be processed.

  This version searches through the file in a linear fashion, with multiple
    token sets and callbacks.
*******************************************************************************/
#include "Parser.h"
#include <stdio.h>    /* printf()         */
#include <stdlib.h>   /* *alloc(), free() */

char *PrintString (Parser &p, char *sp, void *unused);
char *PrintCComment(Parser &p, char *sp, void *unused);
char *PrintCPPComment(Parser &p, char *sp, void *unused);

int main(int argc, char *argv[])
{
  int    tset_strings;
  int    tset_comments;
  int    tset_cpp_comments;
  char  *buffer;
  Parser p(0);

    /* Initalize the parser */
  if(argc == 1)
    p.LoadFile("Parser.cpp"); /* No file specified. Assume Parser.cpp     */
  else
    p.LoadFile(argv[1]);      /* Attempt to load what ever is specified   */

    /* Create a token set for each processing mode */
  tset_strings      = p.AddTokenSet();
  tset_comments     = p.AddTokenSet();
  tset_cpp_comments = p.AddTokenSet();

    /* Switch back to the intial token set, and define our base syntax */
  p.SetTokenSet(0);
  p.AddTokenSeparator("\"", 0, tset_strings,      0, PrintString ,    0);
  p.AddTokenSeparator("/*", 0, tset_comments,     0, PrintCComment,   0);
  p.AddTokenSeparator("//", 0, tset_cpp_comments, 0, PrintCPPComment, 0);

    /* Set up the token set that will handle the strings. This token set will *
     *   be switched to when ever a " is found.                               */
  p.SetTokenSet(tset_strings);
  p.AddTokenSeparator("\\\\", 0, -1, 1, 0, 0); /* Ignore \\                   */
  p.AddTokenSeparator("\\\"", 0, -1, 1, 0, 0); /* Ignore \"                   */
  p.AddTokenSeparator("\"",   0,  0, 0, 0, 0); /* Terminating "               */

    /* Set up the token set that will handle all C comments. This token set   *
     *   will be switched to when ever a / * is found.                        */
  p.SetTokenSet(tset_comments);
  p.AddTokenSeparator("*/",   0,  0, 0, 0, 0); /* Continue until * / is found.*/

    /* Set up the token set that will handle all C++ comments. This token set *
     *   will be switched to when ever a // is found.                         */
  p.SetTokenSet(tset_cpp_comments);
  p.AddTokenSeparator("\n",   0,  0, 0, 0, 0); /* Continue until \n is found. */
  p.AddTokenSeparator("\r",   0,  0, 0, 0, 0); /* Continue until \r is found. */

    /* Switch back to the original token set, since that holds the inital     *
     *   logic set.                                                           */
  p.SetTokenSet(0);

    /* Loop through all the code. GrabToken() will return chunks of code      *
     *   so, we need to free it until we get a null buffer/end of file        */
  for(buffer = p.GrabToken(); buffer; buffer = p.GrabToken())
    free(buffer);

  return 0;
}

  /* This function will be called by the Parser when ever a " is found.       */
char *PrintString(Parser &p, char *sp, void *unused)
{
  /* From here, sp should contain a quotation mark, and we should be in       *
   *   token set tset_strings (1).                                            */

   /* Grab the next token from the stream. Based on the defined logic, this   *
    *   will be everything up to the next "                                   */
  char *buffer = p.GrabToken();
  printf("String Found!\n\"%s\"\n\n", buffer);

    /* Free the pointer, since we own it. */
  free(buffer);

    /* Since we defined the quotation mark to not be returned, the Parser     *
     *   will automatically free sp for us; however, we can free it ourselves *
     *   and return a 0 instead. This would be a more explicit.               */
  return sp;
}

char *PrintCComment(Parser &p, char *sp, void *unused)
{
  char *buffer = p.GrabToken();
  printf("C Style Comment--------------------\n/*%s*/\n\n", buffer);
  free(buffer);

  return sp;
}

char *PrintCPPComment(Parser &p, char *sp, void *unused)
{
  char *buffer = p.GrabToken();
  printf("C++ Style Comment------------------\n//%s\n\n", buffer);
  free(buffer);

  return sp;
}

/************************************************************************
 * End of Program                                                       *
 ************************************************************************/
